﻿using System.IO;
using Framework.Core.Io;
using Framework.Core.Process;
using Xunit;

namespace Framework.Tests.Core.Io
{
    public class ProcessRunnerTest
    {
        private class CommandTest : ICommand
        {
            public CommandTest(string name)
                : this(name, name, string.Empty)
            {

            }

            public CommandTest(string name, string fileName, string arguments)
            {
                FileName = fileName;
                Arguments = arguments;
                Name = name;
            }

            public int ProcessId { get { return 0; } }
            public string Name { get; private set; }
            public string FileName { get; private set; }
            public string Arguments { get; private set; }
            public bool IsNative { get { return false; } }
        }

        private readonly ProcessRunner processRunner;
        private const string FrameworkProcessbenchExe = "Framework.ProcessBench.exe";

        static ProcessRunnerTest()
        {
            var toDeploy = typeof(ProcessRunnerTest).Assembly.GetManifestResourceStream("Framework.Tests.Core.Io.Framework.ProcessBench.exe");
            Assert.NotNull(toDeploy);

            if (!File.Exists(FrameworkProcessbenchExe))
            {
                using (var fileStream = File.Open(FrameworkProcessbenchExe, FileMode.Create, FileAccess.Write))
                {
                    toDeploy.CopyTo(fileStream);
                }
            }
        }

        public ProcessRunnerTest()
        {
            processRunner = new ProcessRunner();
        }

        [Fact]
        public void Should_timeout_if_exceed()
        {
            var processResult = processRunner.Start(new CommandTest(FrameworkProcessbenchExe, FrameworkProcessbenchExe, "Timeout"), 100);

            Assert.True(processResult.IsTimeout);
        }

        [Fact]
        public void Should_not_hang_when_reading_ouput_and_error()
        {
            var processResultException = Assert.Throws<ProcessResultException>(() => processRunner.Start(new CommandTest(FrameworkProcessbenchExe)));
            Assert.Equal(0, processResultException.ExitCode);
            Assert.NotEmpty(processResultException.StandardOuput);
            Assert.NotEmpty(processResultException.ErrorOuput);
        }

        [Fact]
        public void Should_not_throw_if_exit_code_less_0()
        {
            var processResultException = Assert.Throws<ProcessResultException>(() => processRunner.Start(new CommandTest(FrameworkProcessbenchExe, FrameworkProcessbenchExe, "ExitCodeTest")));
            Assert.Equal(-1, processResultException.ExitCode);
            Assert.Empty(processResultException.StandardOuput);
            Assert.Empty(processResultException.ErrorOuput);
        }

        [Fact]
        public void Should_test_as_normal()
        {
            var processResult = processRunner.Start(new CommandTest(FrameworkProcessbenchExe, FrameworkProcessbenchExe, "ExitCode10"));
            Assert.Equal(10, processResult.ExitCode);
            Assert.Empty(processResult.StandardOutput);
            Assert.Empty(processResult.ErrorOutput);
        }
    }
}
